package seTOee.reflact;

import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectTest {
        /*
        * 获取构造器
        * */
        @Test
    public void getConstructorInfo() throws Exception{
            //1、获取类的字节码对象-->泛型类
            Class<Student> c= Student.class;
            //2、获取全部的构造器对象
            //getConstructors()只能获取到公有构造器
            //getDeclaredConstructors()获取所有构造器
//            Constructor<?>[] cons = c.getDeclaredConstructors();
//            for (Constructor<?> constructor : cons) {
//                System.out.println(constructor.getName()+"("+constructor.getParameterCount()+")");
//            }
//            System.out.println("===========================");
            //3、获取指定的构造器对象
            //获取无参构造器对象
            Constructor<Student> con = c.getConstructor();
            System.out.println(con.getName()+"("+con.getParameterCount()+")");

            //获取带参构造器对象
            Constructor<Student> con1 = c.getDeclaredConstructor(String.class, int.class, double.class);
            System.out.println(con1.getName()+"("+con1.getParameterCount()+")");
            System.out.println("===========================");

            //4、通过构造器对象创建对象
            //有参
            con1.setAccessible(true);//暴力访问,忽略访问权限修饰符
            Student s = con1.newInstance("张三",25,100);
            System.out.println(s);

            //无参
            Student s2 = con.newInstance();
            System.out.println(s2);
        }

        /*
        * 获取成员变量
        * */
        @Test
        public void getFieldInfo() throws Exception {
            //1、获取Class对象
            Class<Student> c= Student.class;
            //2、获取所有成员变量
//            Field[] fields = c.getDeclaredFields();
//            for (Field field : fields) {
//                System.out.println(field);
//            }
//            System.out.println("----------------------------------");
            //3、获取指定的成员变量
            Field name = c.getDeclaredField("name");
            System.out.println(name.getName()+":"+name.getType());
            Field age= c.getDeclaredField("age");
            System.out.println(age.getName()+":"+age.getType());
            System.out.println("----------------------------------");

            //4、设置成员变量的值
            Student s = new Student();
            System.out.println(s);
            name.setAccessible(true);
            name.set(s,"张三");
            System.out.println(name.get(s));
            System.out.println(s);
            System.out.println("----------------------------------");
            age.setAccessible(true);
            age.set(s,18);
            System.out.println(age.get(s));
            System.out.println(s);
        }
        /*
        * 获取成员方法
        * */
    @Test
    public void getMethodInfo() throws Exception {
        //1、获取Class对象
        Class<Student> c = Student.class;
        //2、获取所有成员方法
//        Method[] methods = c.getDeclaredMethods();
//        for (Method method : methods) {
//            System.out.println(method);
//        }
//        System.out.println("----------------------------------");
        //3、获取指定的成员方法
        //无参数，无返回值
        Method show = c.getDeclaredMethod("show");
        System.out.println(show);
        //带参数，无返回值
        //参数：参数类型.参数名
        Method show1 = c.getDeclaredMethod("show1", String.class);
        System.out.println(show1);
        Method display = c.getDeclaredMethod("display",String.class, int.class);
        System.out.println(display);
        System.out.println("--------------------------------------");

        //4、调用方法
        //创建对象
        Student s = new Student();

        //无参数，无返回值
        show.setAccessible(true);
        show.invoke(s);//相当于s.show()
        //----------------------------------
        //有参数，无返回值
        show1.setAccessible(true);
        show1.invoke(s,"张三");
        //----------------------------------
        //有参数，有返回值
        display.setAccessible( true);
        Object o = display.invoke(s,"李四",25);
        System.out.println(o);
    }
}
/*
* 反射的作用：
*   可以获得类的所有属性
*   可以破坏封装性
*   绕过泛型的约束
*   可以实现框架
* 反射的应用场景：
*   1. 框架开发
*   2. 测试框架
*   3. 配置文件解析
*   4. 动态代理
* */
